package com.xtpt.disaster.utils;

import org.apache.commons.exec.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.concurrent.TimeUnit;

public class ShellExec {
    /*
    Switch true的话是开启Command方法执行命令，如果false的话开启java自带的process类中的方法执行命令行
    */
    //private static final boolean Switch = true;

    private static final Logger logger = LoggerFactory.getLogger(ShellExec.class);
    /*
    调用processExe，输入执行命令shellString的进程process，
     */
    public static Boolean callShell(String shellString, String resultKey) {
        logger.debug("------------------------cmd:{}", shellString);
        //Boolean result = Boolean.valueOf(true);
        return processExe(shellString, resultKey);

    }

    /*
    与前面的callShell不同，此处的cmd参数是字符串数组，也是记录
     */
    public static Boolean callShell(String[] cmd, String resultKey) {
        logger.debug("*************************************cmd:{}", cmd.toString());
        return processExe(cmd, resultKey);
    }
    /*
    获取进程的执行状态，在规定的时间内执行成功，返回True并销毁进程，未在规定时间内执行成功，返回false也销毁进程。
     */
    private static  boolean processExe(Process process,String resultKey) throws InterruptedException{
        printMessage(process,process.getErrorStream(),resultKey);
        printMessage(process,process.getInputStream(),resultKey);
        boolean res = process.waitFor(30, TimeUnit.SECONDS);
        if (!res) {
            process.destroy();
            return false;
        }
        process.destroy();
        return true;
    }

    public static Boolean callShell(String cmd) {
        return callShell(cmd, null);
    }

    public static Boolean callShell(String[] cmd) {
        return callShell(cmd, null);
    }

    private static void printMessage(final Process process, final InputStream input, String resultKey) {
        Thread t = new Thread(() -> {
            InputStreamReader reader = new InputStreamReader(input);
            BufferedReader bf = new BufferedReader(reader);
            OutputStreamWriter writer = new OutputStreamWriter(process.getOutputStream());
            BufferedWriter bw = new BufferedWriter(writer);
            String line;
            try {
                while (process.isAlive()) {
                    line = bf.readLine();
                    if (line == null)
                        TimeUnit.SECONDS.sleep(1);
                    assert line != null;
                    if(line.contains("[y/n]")){
                        bw.write("y");
                        bw.newLine();
                    }
                }
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            } // TODO Auto-generated catch block

        });
        t.start();
    }

    /*
    @SuppressWarnings("unused")   用于抑制编译器产生警告信息
     */
    @SuppressWarnings("unused")
    private static void inputMessage(final OutputStream output, final Process process) {
        //
        new Thread(() -> {
            OutputStreamWriter writer = new OutputStreamWriter(output);
            BufferedWriter bw = new BufferedWriter(writer);
            //String line = null;
            try {
                while (process.isAlive()) {
                    bw.write("y");
                    bw.newLine();
                    TimeUnit.SECONDS.sleep(3);

                }
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            } // TODO Auto-generated catch block

        }).start();
    }

    private static void inputMessage(final OutputStream output, final ExecuteWatchdog wa) {
        new Thread(() -> {
            OutputStreamWriter writer = new OutputStreamWriter(output);
            BufferedWriter bw = new BufferedWriter(writer);
            //String line = null;
            try {
                while (wa.isWatching()) {
                    bw.write("y");
                    bw.newLine();
                    TimeUnit.SECONDS.sleep(3);

                }
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            } // TODO Auto-generated catch block

        }).start();
    }

    /***
     * 重载的方法
     * ***/
    //@SuppressWarnings("unused")
    private static boolean processExe(String[] cmd, String resultKey) {
        StringBuilder command = new StringBuilder();
        for (String c : cmd) {
            command.append(" ").append(c);
        }
        return processExe(command.toString(), resultKey);
    }

    /***
     * 重载的方法
     * ***/
    private static boolean processExe(String cmd, String resultKey) {
        String out = command(cmd);
        System.out.print(out);
        if (resultKey == null)
            return true;
        return out.contains(resultKey);
    }

    /***
     * common-exec 执行命令行
     * @param command 要执行的命令
     * @return 返回命令行输出的内容。
     * **/
    public static String command(String command) {
        try {
            //String command = "ping "+ip;

            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
            ByteArrayInputStream inputStream = new ByteArrayInputStream("y".getBytes());
            /*
            CommandLine.parse(command)  生成command字符串对应的命令
            DefaultExecu exec = new DefaultExecutor();  生成命令行执行器
            exec.setExitValue(1)  设置程序执行退出值
             */
            CommandLine commandline = CommandLine.parse(command);
            DefaultExecutor exec = new DefaultExecutor();
            ExecuteWatchdog watchdog = new ExecuteWatchdog(20 * 1000);//等待20秒，超时推出
            exec.setExitValue(1);
            //PumpStreamHandler，截获进程的各种输出，包括output 和 error stream
            PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream, errorStream, inputStream);
            exec.setWatchdog(watchdog);
            //System.out.println("commandline:"+commandline);
            exec.setStreamHandler(streamHandler);
            /*
            DefaultExecuteResultHandler 处理外部命令执行的结果，释放当前线程，是当前线程不被阻塞
             */
            DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();

            exec.execute(commandline, resultHandler);
            inputMessage(outputStream, watchdog);


            resultHandler.waitFor(60000);

            String out = outputStream.toString("gbk");
            String error = errorStream.toString("gbk");
//
            return out + error;
        } catch (Exception e) {
            logger.error("ping task failed.", e);
            return e.getMessage();
        }
    }
}